import os
import sys
import shutil
import subprocess
import uuid
import platform
from typing import List, Optional
from fastapi import APIRouter, File, UploadFile, HTTPException, BackgroundTasks, Form, Request
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
import logging
from datetime import datetime

# 配置日志
logger = logging.getLogger("libreoffice-converter")

# 创建路由器
router = APIRouter(
    prefix="/api",
    tags=["converter"],
)

# 定义响应模型
class ConversionResponse(BaseModel):
    success: bool
    message: str
    output_file: Optional[str] = None
    job_id: Optional[str] = None
    url: Optional[str] = None

class ConversionStatus(BaseModel):
    job_id: str
    status: str
    output_file: Optional[str] = None
    message: Optional[str] = None

# 存储后台任务状态
conversion_jobs = {}

# 获取系统信息
SYSTEM = platform.system()
IS_WINDOWS = SYSTEM == "Windows"

# 基础目录
BASE_TEMP_DIR = "temp"
BASE_OUTPUT_DIR = "output"

# 获取LibreOffice可能的路径
def get_libreoffice_paths():
    """根据操作系统获取LibreOffice可能的路径"""
    paths = []
    
    if IS_WINDOWS:
        # Windows上常见的LibreOffice安装路径
        program_files = os.environ.get("ProgramFiles", "C:\\Program Files")
        program_files_x86 = os.environ.get("ProgramFiles(x86)", "C:\\Program Files (x86)")
        
        possible_paths = [
            os.path.join(program_files, "LibreOffice", "program", "soffice.exe"),
            os.path.join(program_files_x86, "LibreOffice", "program", "soffice.exe"),
            os.path.join(program_files, "LibreOffice 7", "program", "soffice.exe"),
            os.path.join(program_files_x86, "LibreOffice 7", "program", "soffice.exe"),
            # 添加其他可能的路径
        ]
        
        for path in possible_paths:
            if os.path.exists(path):
                paths.append(path)
                
        # 如果没有找到安装路径，也添加命令名称，以便在PATH中查找
        if not paths:
            paths = ["soffice.exe", "soffice"]
    else:
        # Linux/Unix系统的命令
        paths = ["libreoffice", "soffice"]
        
        # 检查常见的安装路径
        possible_paths = [
            "/usr/bin/libreoffice",
            "/usr/bin/soffice",
            "/opt/libreoffice/program/soffice",
        ]
        
        for path in possible_paths:
            if os.path.exists(path):
                paths.append(path)
    
    return paths

# 文件转换函数
def convert_to_pdf(input_file, output_dir="output", debug=True):
    """使用 LibreOffice 将文件转换为 PDF"""
    # 确保输入文件存在
    if not os.path.exists(input_file):
        logger.error(f"错误: 输入文件 '{input_file}' 不存在")
        return None
    
    # 确保输出目录存在
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    # 获取绝对路径
    input_file_abs = os.path.abspath(input_file)
    output_dir_abs = os.path.abspath(output_dir)
    
    # 构造输出 PDF 路径
    output_filename = os.path.splitext(os.path.basename(input_file))[0] + ".pdf"
    output_file = os.path.join(output_dir_abs, output_filename)
    
    if debug:
        logger.info(f"操作系统: {SYSTEM}")
        logger.info(f"输入文件: {input_file_abs}")
        logger.info(f"输出目录: {output_dir_abs}")
    
    try:
        # 获取可能的LibreOffice路径
        libreoffice_paths = get_libreoffice_paths()
        
        if debug:
            logger.info(f"尝试的LibreOffice路径: {libreoffice_paths}")
        
        # 在容器内或本地执行LibreOffice命令
        if debug:
            logger.info("执行LibreOffice转换命令...")
            
        success = False
        error_messages = []
        
        for cmd_path in libreoffice_paths:
            if debug:
                logger.info(f"尝试使用命令: {cmd_path}")
            
            # 构建命令    
            if IS_WINDOWS:
                # Windows特殊处理
                cmd = [
                    cmd_path,
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", f'"{output_dir_abs}"',
                    f'"{input_file_abs}"'
                ]
                cmd_str = " ".join(cmd)
                
                try:
                    # 在Windows上使用shell=True可能更可靠
                    result = subprocess.run(cmd_str, capture_output=True, text=True, timeout=60, shell=True)
                    if result.returncode == 0:
                        success = True
                        if debug:
                            logger.info(f"命令执行成功: {cmd_path}")
                            logger.info(f"输出: {result.stdout}")
                        break
                    else:
                        error_msg = f"命令执行失败: {cmd_path}, 错误: {result.stderr}"
                        error_messages.append(error_msg)
                        if debug:
                            logger.error(error_msg)
                except subprocess.TimeoutExpired:
                    error_msg = f"命令执行超时: {cmd_path}"
                    error_messages.append(error_msg)
                    logger.error(error_msg)
                    continue
                except Exception as e:
                    error_msg = f"执行命令时发生异常: {cmd_path}, 错误: {str(e)}"
                    error_messages.append(error_msg)
                    logger.error(error_msg)
                    continue
            else:
                # Linux/Unix命令
                cmd = [
                    cmd_path,
                    "--headless",
                    "--convert-to", "pdf",
                    "--outdir", output_dir_abs,
                    input_file_abs
                ]
                
                try:
                    result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
                    if result.returncode == 0:
                        success = True
                        if debug:
                            logger.info(f"命令执行成功: {cmd_path}")
                            logger.info(f"输出: {result.stdout}")
                        break
                    else:
                        error_msg = f"命令执行失败: {cmd_path}, 错误: {result.stderr}"
                        error_messages.append(error_msg)
                        if debug:
                            logger.error(error_msg)
                except subprocess.TimeoutExpired:
                    error_msg = f"命令执行超时: {cmd_path}"
                    error_messages.append(error_msg)
                    logger.error(error_msg)
                    continue
                except Exception as e:
                    error_msg = f"执行命令时发生异常: {cmd_path}, 错误: {str(e)}"
                    error_messages.append(error_msg)
                    logger.error(error_msg)
                    continue
        
        if not success:
            logger.error("所有LibreOffice命令尝试均失败")
            logger.error(f"错误信息汇总: {error_messages}")
            
            # 如果是Windows系统，给出安装建议
            if IS_WINDOWS:
                logger.error("请确保已安装LibreOffice，并将其添加到PATH环境变量中")
                logger.error("LibreOffice下载地址: https://www.libreoffice.org/download/download/")
            
            return None
        
        # 检查文件是否成功生成
        if os.path.exists(output_file):
            logger.info(f"成功转换: {input_file} -> {output_file}")
            return output_file
        else:
            logger.error(f"转换可能成功，但找不到输出文件: {output_file}")
            return None
            
    except Exception as e:
        logger.exception(f"转换过程中发生异常: {str(e)}")
        return None

# 批量转换函数
def batch_convert_to_pdf(input_dir, output_dir="output"):
    """批量转换目录中的文件为PDF"""
    if not os.path.exists(input_dir):
        logger.error(f"输入目录不存在: {input_dir}")
        return []
    
    results = []
    for filename in os.listdir(input_dir):
        input_path = os.path.join(input_dir, filename)
        if os.path.isfile(input_path):
            result = convert_to_pdf(input_path, output_dir)
            if result:
                results.append(result)
    
    return results

# 后台任务处理函数
def background_conversion(job_id: str, input_file: str, output_dir: str):
    """在后台执行文件转换任务"""
    try:
        conversion_jobs[job_id]["status"] = "processing"
        output_file = convert_to_pdf(input_file, output_dir)
        
        if output_file:
            conversion_jobs[job_id]["status"] = "completed"
            conversion_jobs[job_id]["output_file"] = output_file
        else:
            conversion_jobs[job_id]["status"] = "failed"
            conversion_jobs[job_id]["message"] = "转换失败"
    except Exception as e:
        conversion_jobs[job_id]["status"] = "failed"
        conversion_jobs[job_id]["message"] = str(e)
        logger.exception(f"后台任务执行失败: {str(e)}")

# API路由
@router.post("/convert", response_model=ConversionResponse)
async def convert_file(
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    async_mode: bool = Form(False)
):
    """
    上传文件并转换为PDF
    - **file**: 要转换的文件
    - **async_mode**: 是否异步处理（默认为False）
    """
    # 创建临时目录存储上传文件
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    folder_id = uuid.uuid4().hex[:8]
    
    # 将临时目录放在base_temp_dir下
    temp_folder_name = f"{timestamp}_{folder_id}"
    temp_dir = os.path.join(BASE_TEMP_DIR, temp_folder_name)
    os.makedirs(temp_dir, exist_ok=True)
    
    # 将输出目录放在base_output_dir下
    output_folder_name = f"{timestamp}_{folder_id}"
    output_dir = os.path.join(BASE_OUTPUT_DIR, output_folder_name)
    os.makedirs(output_dir, exist_ok=True)
    
    # 保存上传的文件
    file_path = os.path.join(temp_dir, file.filename)
    with open(file_path, "wb") as buffer:
        buffer.write(await file.read())
    
    # 处理异步模式
    if async_mode:
        job_id = str(uuid.uuid4())
        conversion_jobs[job_id] = {
            "status": "pending",
            "input_file": file_path,
            "output_dir": output_dir,
            "timestamp": datetime.now().isoformat()
        }
        
        background_tasks.add_task(
            background_conversion,
            job_id=job_id,
            input_file=file_path,
            output_dir=output_dir
        )
        
        return ConversionResponse(
            success=True,
            message="文件已接收，正在后台处理",
            job_id=job_id
        )
    
    # 同步模式直接处理
    output_file = convert_to_pdf(file_path, output_dir)
    
    if output_file:
        return ConversionResponse(
            success=True,
            message="文件转换成功",
            output_file=output_file
        )
    else:
        raise HTTPException(status_code=500, detail="文件转换失败")

@router.post("/convert2pdf_url", response_model=ConversionResponse)
async def convert_file_with_url(
    request: Request,
    background_tasks: BackgroundTasks,
    file: UploadFile = File(...),
    async_mode: bool = Form(False)
):
    """
    上传文件并转换为PDF，返回文件的URL
    - **file**: 要转换的文件
    - **async_mode**: 是否异步处理（默认为False）
    
    返回:
    - 成功时返回转换后PDF文件的URL
    """
    # 创建临时目录存储上传文件
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    folder_id = uuid.uuid4().hex[:8]
    
    # 将临时目录放在base_temp_dir下
    temp_folder_name = f"{timestamp}_{folder_id}"
    temp_dir = os.path.join(BASE_TEMP_DIR, temp_folder_name)
    os.makedirs(temp_dir, exist_ok=True)
    
    # 将输出目录放在base_output_dir下
    output_folder_name = f"{timestamp}_{folder_id}"
    output_dir = os.path.join(BASE_OUTPUT_DIR, output_folder_name)
    os.makedirs(output_dir, exist_ok=True)
    
    # 保存上传的文件
    file_path = os.path.join(temp_dir, file.filename)
    with open(file_path, "wb") as buffer:
        buffer.write(await file.read())
    
    # 处理异步模式
    if async_mode:
        job_id = str(uuid.uuid4())
        conversion_jobs[job_id] = {
            "status": "pending",
            "input_file": file_path,
            "output_dir": output_dir,
            "timestamp": datetime.now().isoformat()
        }
        
        background_tasks.add_task(
            background_conversion,
            job_id=job_id,
            input_file=file_path,
            output_dir=output_dir
        )
        
        return ConversionResponse(
            success=True,
            message="文件已接收，正在后台处理",
            job_id=job_id
        )
    
    # 同步模式直接处理
    output_file = convert_to_pdf(file_path, output_dir)
    
    if not output_file:
        raise HTTPException(status_code=500, detail="文件转换失败")
    
    # 构建文件URL
    # 获取主机和端口
    host = request.headers.get("host", "localhost:8001")
    # 获取协议
    protocol = "https" if request.url.scheme == "https" else "http"
    # 构建相对路径
    relative_path = os.path.relpath(output_file, start=os.getcwd())
    # 替换Windows路径分隔符
    relative_path = relative_path.replace("\\", "/")
    
    # 构建文件下载URL
    file_url = f"{protocol}://{host}/api/download?file_path={relative_path}"
    
    return ConversionResponse(
        success=True,
        message="文件转换成功",
        output_file=output_file,
        job_id=None,
        url=file_url  # 返回文件URL
    )


@router.get("/status/{job_id}", response_model=ConversionStatus)
def get_conversion_status(job_id: str):
    """
    获取转换任务的状态
    - **job_id**: 任务ID
    """
    if job_id not in conversion_jobs:
        raise HTTPException(status_code=404, detail=f"找不到任务ID: {job_id}")
    
    job = conversion_jobs[job_id]
    return ConversionStatus(
        job_id=job_id,
        status=job["status"],
        output_file=job.get("output_file"),
        message=job.get("message")
    )

@router.get("/download/{job_id}")
def download_converted_file(job_id: str):
    """
    下载转换后的文件
    - **job_id**: 任务ID
    """
    if job_id not in conversion_jobs:
        raise HTTPException(status_code=404, detail=f"找不到任务ID: {job_id}")
    
    job = conversion_jobs[job_id]
    if job["status"] != "completed":
        raise HTTPException(status_code=400, detail=f"任务尚未完成，当前状态: {job['status']}")
    
    if not os.path.exists(job["output_file"]):
        raise HTTPException(status_code=404, detail="找不到转换后的文件")
    
    return FileResponse(
        job["output_file"],
        filename=os.path.basename(job["output_file"]),
        media_type="application/pdf"
    )

@router.get("/download")
def download_file(file_path: str):
    """
    下载指定路径的文件
    - **file_path**: 文件路径
    """
    if not os.path.exists(file_path):
        raise HTTPException(status_code=404, detail=f"找不到文件: {file_path}")
    
    return FileResponse(
        file_path,
        filename=os.path.basename(file_path),
        media_type="application/pdf"
    )

@router.post("/batch", response_model=ConversionResponse)
def batch_convert(input_dir: str = Form(...), output_dir: str = Form(BASE_OUTPUT_DIR)):
    """
    批量转换目录中的文件
    - **input_dir**: 输入目录
    - **output_dir**: 输出目录（默认为'output'）
    """
    if not os.path.exists(input_dir):
        raise HTTPException(status_code=404, detail=f"输入目录不存在: {input_dir}")
    
    # 为批量任务创建专用输出目录
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    folder_id = uuid.uuid4().hex[:8]
    batch_output_dir = os.path.join(output_dir, f"batch_{timestamp}_{folder_id}")
    os.makedirs(batch_output_dir, exist_ok=True)
    
    results = batch_convert_to_pdf(input_dir, batch_output_dir)
    
    if results:
        return ConversionResponse(
            success=True,
            message=f"批量转换成功，共转换 {len(results)} 个文件",
            output_file=str(results)
        )
    else:
        raise HTTPException(status_code=500, detail="批量转换失败或没有文件被转换")

@router.get("/system-info")
def get_system_info():
    """获取系统信息"""
    libreoffice_paths = get_libreoffice_paths()
    found_paths = []
    
    for path in libreoffice_paths:
        if os.path.exists(path):
            found_paths.append(path)
    
    return {
        "system": SYSTEM,
        "is_windows": IS_WINDOWS,
        "libreoffice_paths": libreoffice_paths,
        "found_paths": found_paths,
        "python_version": sys.version,
        "working_directory": os.getcwd(),
        "temp_dir": BASE_TEMP_DIR,
        "output_dir": BASE_OUTPUT_DIR
    }